// 获取当前时间戳
const now = () => {
  if (performance && performance.now) return performance.now();
  return new Date().getTime();
};

/**
 * 动画类
 */
export default class Animation {
  className = 'Animation'; // 类名
  constructor(func, stage) {
    this.id = Animation.animIdCounter++;
    // 动画帧
    this.frame = {
      time: 0, // 动画执行的时间
      timeDiff: 0, // 上一帧与当前帧的时间差
      lastTime: now(), // 记录上一帧的时间
      frameRate: 0, // 帧率
    };
    // 动画帧回调函数
    this.func = func;
    this.stage = stage;
  }
  /**
   * Methods
   */
  // 动画是否执行中
  isRunning() {
    return Animation.animations.some((i) => i.id === this.id);
  }
  // 执行动画
  start() {
    this.stop();
    this.frame.timeDiff = 0;
    this.frame.lastTime = now();
    Animation.addAnimation(this);
    return this;
  }
  // 停止动画
  stop() {
    Animation.removeAnimation(this);
    return this;
  }
  // 更新动画帧对象
  updateFrameObject(time) {
    this.frame.timeDiff = time - this.frame.lastTime;
    this.frame.lastTime = time;
    this.frame.time += this.frame.timeDiff;
    this.frame.frameRate = 1000 / this.frame.timeDiff;
  }
  /**
   * Static Methods
   */
  // 新增动画实例
  static addAnimation(anim) {
    this.animations.push(anim);
    this.handleAnimation();
  }
  // 移除动画实例
  static removeAnimation(anim) {
    const index = this.animations.findIndex((i) => i.id === anim.id);
    if (index > -1) this.animations.splice(index, 1);
  }
  // 运行动画帧
  static runFrames() {
    const stages = [];
    this.animations.forEach((anim) => {
      const { func, stage } = anim;
      anim.updateFrameObject(now());
      if (func?.call(anim, anim.frame) === false) return;
      if (stage) stages.push(stage);
    });
    [...new Set(stages)].forEach((stage) => stage.draw());
  }
  // 动画循环
  static animationLoop() {
    if (this.animations.length) {
      this.runFrames();
      requestAnimationFrame(() => this.animationLoop());
    } else {
      this.animRunning = false;
    }
  }
  // 执行动画
  static handleAnimation() {
    if (this.animRunning) return;
    this.animRunning = true;
    requestAnimationFrame(() => this.animationLoop());
  }
}

Animation.animations = [];
Animation.animIdCounter = 0;
Animation.animRunning = false;
